/*
 * INCLUDE FILES
 ****************************************************************************************
 */
#include <stdio.h>
#include <string.h>

#include "gap_api.h"
#include "gatt_api.h"
#include "ble_stack.h"

#include "app_config.h"

#include "co_printf.h"
#include "co_log.h"

#include "driver_system.h"
#include "driver_pmu.h"
#include "driver_uart.h"
#include "driver_gpio.h"

#include "plf.h"

#include "gpio_demo.h"

#undef LOG_LOCAL_LEVEL
#define LOG_LOCAL_LEVEL        (LOG_LEVEL_INFO)
const char *app_tag = "project";

#define SYSTEM_STACK_SIZE           0x800

__attribute__((section("stack_section"))) static uint32_t system_stack[SYSTEM_STACK_SIZE/sizeof(uint32_t)];

const struct jump_table_version_t _jump_table_version __attribute__((section("jump_table_3"))) = 
{
    .stack_top_address = &system_stack[SYSTEM_STACK_SIZE/sizeof(uint32_t)],
    .firmware_version = 0x00000000,
};

const struct jump_table_image_t _jump_table_image __attribute__((section("jump_table_1"))) =
{
    .image_type = IMAGE_TYPE_APP,
    .image_size = 0x19000,
};

/*********************************************************************
 * @fn      user_entry_before_sleep_imp
 *
 * @brief   Before system goes to sleep mode, user_entry_before_sleep_imp()
 *          will be called, MCU peripherals can be configured properly before 
 *          system goes to sleep, for example, some MCU peripherals need to be
 *          used during the system is in sleep mode. 
 *
 * @param   None. 
 *       
 *
 * @return  None.
 */
__attribute__((section("ram_code"))) void user_entry_before_sleep_imp(void)
{
	co_printf("sleep\r\n");
	co_delay_100us(10);
}

/*********************************************************************
 * @fn      user_entry_after_sleep_imp
 *
 * @brief   After system wakes up from sleep mode, user_entry_after_sleep_imp()
 *          will be called, MCU peripherals need to be initialized again, 
 *          this can be done in user_entry_after_sleep_imp(). MCU peripherals
 *          status will not be kept during the sleep. 
 *
 * @param   None. 
 *       
 *
 * @return  None.
 */
__attribute__((section("ram_code"))) void user_entry_after_sleep_imp(void)
{
    system_set_port_mux(GPIO_PORT_A, GPIO_BIT_0, PORTA0_FUNC_UART0_RXD);
    system_set_port_mux(GPIO_PORT_A, GPIO_BIT_1, PORTA1_FUNC_UART0_TXD);
    uart_init(UART0, 1152);
	
	co_printf("wakeup\r\n");
	co_delay_100us(10);
	
	system_sleep_disable();
}

__attribute__((section("ram_code"))) void main_loop(void)
{
    while(1)
    {
        if(ble_stack_schedule_allow())
        {
            /*user code should be add here*/
			co_printf("MCU Runing \r\n");
			co_delay_100us(1000);
            /* schedule internal stack event */
            ble_stack_schedule();
        }
        
        GLOBAL_INT_DISABLE();
        switch(ble_stack_sleep_check())
        {
            case 2:
            {
                ble_stack_enter_sleep();
            }
            break;
            default:
                break;
        }
        GLOBAL_INT_RESTORE();
        
        ble_stack_schedule_backward();
    }
}

void proj_init(void)
{
    LOG_INFO(app_tag, "proj_init\r\n");
    LOG_INFO(app_tag, "lp clk=%d\r\n", pmu_get_rc_clk(false));

    /* system sleep is allowed */
    system_sleep_disable();

	GLOBAL_INT_START();
}

void user_main(void)
{
    /* initialize log module */
    log_init();

    /* initialize PMU module at the beginning of this program */
    pmu_sub_init();

    /* set system clock */
    system_set_clock(SYSTEM_CLOCK_SEL);

	    /* set local BLE address */
    mac_addr_t mac_addr;
    mac_addr.addr[0] = 0xAA;
    mac_addr.addr[1] = 0xad;
    mac_addr.addr[2] = 0xCC;
    mac_addr.addr[3] = 0x11;
    mac_addr.addr[4] = 0x33;
    mac_addr.addr[5] = 0x30;
    gap_address_set(&mac_addr, BLE_ADDR_TYPE_PRIVATE);
    
    /* configure ble stack capabilities */
    ble_stack_configure(BLE_STACK_ENABLE_MESH,
                        BLE_STACK_ENABLE_CONNECTIONS,
                        BLE_STACK_RX_BUFFER_CNT,
                        BLE_STACK_RX_BUFFER_SIZE, 
                        BLE_STACK_TX_BUFFER_CNT, 
                        BLE_STACK_TX_BUFFER_SIZE, 
                        BLE_STACK_ADV_BUFFER_SIZE,
                        BLE_STACK_RETENTION_RAM_SIZE,
                        BLE_STACK_KEY_STORAGE_OFFSET);
    /* initialize ble stack */
    ble_stack_init();
    /* initialize SMP */
    gap_bond_manager_init(BLE_BONDING_INFO_SAVE_ADDR, BLE_REMOTE_SERVICE_SAVE_ADDR, 8, true);
	
    proj_init();

	/* demo select: GPIO_EXTI_INT */
	/* demo select: GPIO_WAKE_UP  */
 	/* demo select: GOIO_OUTPUT  */  
 	/* demo select: GPIO_INPUT  */   
    
	gpio_demo(GPIO_INPUT);
}
